home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Tool Chest / QuickDraw GX / QuickDraw GX Info / QuickDraw GX Interfaces / Interfaces & Libraries / graphics libraries / font menu library.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-04-30  |  19.0 KB  |  583 lines  |  [TEXT/MPS ]

  1. /* graphics:    
  2.     gxFont menu library routines
  3.     by Cary Clark, Georgiann Delaney, Michael Fairman, Dave Good, Robert Johnson, Keith McGreggor, Mike Reed, Oliver Steele, David Van Brink, Chris Yerga
  4.     Copyright ©1987 - 1991 Apple Computer, Inc.  All rights reserved.
  5. */
  6.  
  7. #include <Resources.h>
  8. #include <Menus.h>
  9. #include <Memory.h>
  10. #include <ToolUtils.h>
  11. #include <Types.h>
  12. #include <Fonts.h>
  13.  
  14. #include "graphics types.h"
  15. #include "font menu library.h"
  16. #include "font routines.h"
  17. #include "font library.h"
  18. #include "graphics routines.h"
  19. #include "layout routines.h"
  20. #if !defined(__powerc)
  21.     pascal Handle XGetNextFOND(Handle fontHandle) = {0x700A, 0xA822}; /* this disappeared in the latest release of THINK C */
  22. #else
  23.     #define XGetNextFOND GetNextFOND
  24. #endif
  25.  
  26. #ifdef MacintoshIncludes
  27. #endif
  28.  
  29.  
  30. /*****************************************
  31.  *  Menu manager library routines to handle fonts *
  32.  *****************************************/
  33.  
  34. static long AppendMenuName(MenuHandle menu, long length, unsigned char name[])
  35. {
  36.     name[0] = length < 255 ? length : 255;
  37.     AppendMenu(menu, (const unsigned char *) "\pfont name");  /*** some full names disable the item */ /* cast for Think C 4.0 */
  38. #if !defined(__powerc) && !defined(ppcinterfaces)
  39.     SetItem(menu, CountMItems(menu), name);
  40. #else
  41.     SetMenuItemText(menu, CountMItems(menu), name);
  42. #endif
  43.     return length > 255;
  44. }
  45.  
  46. static MenuHandle NewMenuName(short menuID, long length, unsigned char *title)
  47. {
  48.     Str255 str;
  49.  
  50.     str[0] = length < 255 ? length : 255;
  51.     BlockMove(title+1, &str[1], str[0]);
  52.     return NewMenu(menuID, str);
  53. }
  54.  
  55. static int Str255Compare(Str255 a, Str255 b)
  56. {
  57.     int i, minSize = a[0] < b[0] ? a[0] : b[0];
  58.  
  59.     for (i = 1; i < minSize; i++) {
  60.         if (a[i] == b[i])
  61.             continue;
  62.         return a[i] - b[i];
  63.     }
  64.     return a[0] - b[0];
  65. }
  66.  
  67. /*
  68. *       sorts the text, command char, and item mark 
  69. *       this way any submenus will sort with the  item     
  70.  *  THIS SHOULD CALL SOME COOL INTL. SORT ROUTINE
  71.  */
  72. void SortMenu(MenuHandle menu)
  73. {
  74.     short i, j, count = CountMItems(menu);
  75.     
  76.     for (i = 2; i <= count; i++)
  77.         for (j = count; j >= i; --j) {
  78.             short lowercmdChar, uppercmdChar;
  79.             short lowermarkChar, uppermarkChar;
  80.             Str255 lower, upper;
  81. #if !defined(__powerc) && !defined(ppcinterfaces)
  82.             GetItem(menu, j, lower);
  83.             GetItem(menu, j-1, upper);
  84. #else            
  85.             GetMenuItemText(menu, j, lower);
  86.             GetMenuItemText(menu, j-1, upper);
  87. #endif
  88.             GetItemCmd ( menu, j, &lowercmdChar );
  89.             GetItemCmd ( menu, j-1, &uppercmdChar );
  90.             GetItemMark ( menu, j, &lowermarkChar );
  91.             GetItemMark ( menu, j-1, &uppermarkChar );
  92.             
  93.             if (Str255Compare(lower, upper) < 0) {
  94.  #if !defined(__powerc) && !defined(ppcinterfaces)
  95.                 SetItem(menu, j, upper);
  96.                 SetItem(menu, j-1, lower);
  97.  #else
  98.                 SetMenuItemText(menu, j, upper);
  99.                 SetMenuItemText(menu, j-1, lower);
  100.  #endif
  101.                 SetItemCmd ( menu, j, uppercmdChar );
  102.                 SetItemCmd ( menu, j-1, lowercmdChar );
  103.                 SetItemMark ( menu, j, uppermarkChar );
  104.                 SetItemMark ( menu, j-1, lowermarkChar );
  105.             }
  106.         }
  107. }
  108.  
  109. /*
  110.  *  Append a menu with the fonts' full names
  111.  */
  112. long FontMenu(MenuHandle menu)
  113. {
  114.     return FontPlatformMenu(menu, gxNoPlatform, gxNoScript, gxNoLanguage);
  115. }
  116.  
  117. /*
  118.  *  Append a menu with the fonts' full names for fonts that support the specified platform
  119.  */
  120. long FontPlatformMenu(MenuHandle menu, gxFontPlatform platform, gxFontScript script, gxFontLanguage language)
  121. {
  122.     gxFont* fonts;
  123.     long i, count, nameIndex;
  124.     
  125.     count = GXFindFonts(nil, 0, platform, script, language, 0, nil, 1, gxSelectToEnd, 0);
  126.     fonts = (gxFont*)NewPtr(count * sizeof(gxFont));
  127.     GXFindFonts(nil, 0, platform, script, language, 0, nil, 1, count, fonts);
  128.  
  129.     for (i = 0; i < count; i++)
  130.     {   unsigned char *name; 
  131.         long length;
  132.          
  133.         if ((length = GXFindFontName(fonts[i], gxFullFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, &nameIndex)) > 0) {
  134.             name = (unsigned char *) NewPtr(length + 1);
  135.             GXGetFontName(fonts[i], nameIndex, nil, nil, nil, nil, &name[1]);
  136.             AppendMenuName(menu, length, name);
  137.             DisposePtr((Ptr) name);
  138.         } 
  139.     }
  140.     DisposePtr((Ptr)fonts);
  141.     SortMenu(menu);
  142.     return count;
  143. }
  144.  
  145. /*
  146.  *  Append a menu with the fonts' family names
  147.  */
  148. long FontFamilyMenu(MenuHandle menu)
  149. {
  150.     return FontFamilyPlatformMenu(menu, gxNoPlatform, gxNoScript, gxNoLanguage);
  151. }
  152.  
  153. long FontFamilyPlatformMenu(MenuHandle menu, gxFontPlatform platform, gxFontScript script, gxFontLanguage language)
  154. {
  155.     gxFont* fonts;
  156.     long i, count;
  157.     
  158.     count = GXFindFonts(nil, gxFamilyFontName, platform, script, language, 0, nil, 1, gxSelectToEnd, nil);
  159.     fonts = (gxFont*)NewPtr(count * sizeof(gxFont));
  160.     GXFindFonts(nil, gxFamilyFontName, platform, script, language, 0, nil, 1, count, fonts);
  161.  
  162.     for (i = 0; i < count; i++)
  163.     {    unsigned char name[256];
  164.         
  165.             name[0] = GXFindFontName(fonts[i], gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil);
  166.         if (name[0])
  167.             AppendMenuName(menu, name[0], name);
  168.     }
  169.     DisposePtr((Ptr)fonts);
  170.     SortMenu(menu);
  171.     return count;
  172. }
  173.  
  174. /*
  175.  *  Create a menu with the given gxFont family's name, filled with the styles available in that family
  176.  */
  177. MenuHandle FontStyleMenu(short menuID, gxFont family)
  178. {
  179.     long i, count = CountFontStyles(family);
  180.     long length;
  181.     MenuHandle menu;
  182.     unsigned char *name;
  183.  
  184.     if ((length = GXFindFontName(family, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, nil)) > 0) {
  185.         name = (unsigned char *) NewPtr(length + 1);
  186.         GXFindFontName(family, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil);
  187.         menu = NewMenuName(menuID, length, name);
  188.         DisposePtr((Ptr) name);
  189.     } else
  190.         menu = NewMenu(menuID, (unsigned char *) "\pNo family name");    /* cast for Think C 4.0 */
  191.  
  192.     for (i = 1; i <= count; i++) {
  193.         gxFont sfnt = FindFontStyle(family, i, 0, 0, 0, 0, nil);
  194.         if ((length = GXFindFontName(sfnt, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, nil)) > 0) {
  195.             name = (unsigned char *) NewPtr(length + 1);
  196.             GXFindFontName(sfnt, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil);
  197.             AppendMenuName(menu, length, name);
  198.             DisposePtr((Ptr)name);
  199.         }
  200.     }
  201.     SortMenu(menu);
  202.  
  203.     return menu;
  204. }
  205.  
  206. /*********************************************/
  207. /*                  HierFontMenu                        */
  208. /*                                                  */
  209. /*          the firstHierMenuID let's the application decide        */
  210. /*          what number the heir menu IDs start                     */ 
  211. /*                                                  */
  212. /*********************************************/
  213. short HierFontMenu(MenuHandle theMenu, short firstHierMenuID, fontFilterProc proc, fontMenuAttribute attr)
  214. {
  215.     long        i, count;
  216.     short    heirsUsed = 0;
  217.     long        howManyInstances;
  218.     long        howManyVariations;
  219.     gxFontVariation        *variations;
  220.     gxFontName        fontNameID;
  221.  
  222.     count = GXFindFonts(nil, 0, 0, 0, 0, 0, nil, 1, gxSelectToEnd, 0);
  223.     for (i = 1; i <= count; i++)
  224.     {    gxFont fontID;
  225.         long length;
  226.  
  227.         GXFindFonts(nil, 0, 0, 0, 0, 0, nil, i, 1, &fontID);
  228.         if (proc && !proc(fontID))
  229.             continue;
  230.         length = GXFindFontName(fontID, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, nil);
  231.         if (length)
  232.         {
  233.             unsigned char *name;
  234.             Boolean alreadyInMenu = false;
  235.             short numMItem;
  236.             short k;
  237.  
  238.             name = (unsigned char *) NewPtr(length + 1);
  239.             GXFindFontName(fontID, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil);
  240.             numMItem = CountMItems(theMenu);/*how many items have i already added to the menu*/
  241.             for (k=1; k<= numMItem; k++)    /*check to see if the name is already in the menu*/
  242.             {
  243.                 Str255      str;
  244. #if !defined(__powerc) && !defined(ppcinterfaces)
  245.                 GetItem (theMenu, k, str);
  246. #else
  247.                 GetMenuItemText (theMenu, k, str);
  248. #endif
  249.                 name[0] = length; /*fake str255*/
  250.                 if ( !Str255Compare(str, name) ) 
  251.                     alreadyInMenu = true;
  252.             }
  253.             if (!alreadyInMenu)         /*if not then add it*/
  254.             {
  255.                 MenuHandle hMenu;
  256.  
  257.                 AppendMenuName(theMenu, length, name);
  258.                 hMenu = FontStyleMenu(heirsUsed + firstHierMenuID, fontID);
  259.                 howManyInstances = (attr & noInstancesFontMenu) ? 0 : GXCountFontInstances(fontID);
  260.                 if( ( (CountMItems(hMenu)) > 1) || (howManyInstances > 0) )/*only add it if it is more than one item*/
  261.                 {   
  262.                     InsertMenu (hMenu, -1);
  263.                     
  264.                     SetItemCmd(theMenu, numMItem+1, hMenuCmd);
  265.                     SetItemMark(theMenu, numMItem+1, heirsUsed + firstHierMenuID);
  266.                     heirsUsed ++;
  267.                 }
  268.                 
  269.                 if(howManyInstances)
  270.                 {
  271.                     short m;
  272.                     
  273.                     howManyVariations = GXCountFontVariations(fontID);
  274.                     variations = (gxFontVariation*)NewPtr(sizeof(gxFontVariation) * howManyVariations);
  275.                     
  276.                     AppendMenu(hMenu, (const unsigned char *) "\p(-" );    /*dotted gxLine*/
  277.                     for(m = 1; m<=howManyInstances; m++)
  278.                     {
  279.                         DisposePtr((Ptr) name);
  280.                         fontNameID = GXGetFontInstance(fontID, m, variations);
  281.                         if ((length = GXFindFontName(fontID, fontNameID, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, nil, nil)) > 0) 
  282.                         {
  283.                             name = (unsigned char *) NewPtr(length+1);
  284.                             GXFindFontName(fontID, fontNameID, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, &name[1], nil);
  285.                             AppendMenuName(hMenu, length, name);
  286.                         }
  287.                     }
  288.                 }
  289.             }
  290.             DisposePtr((Ptr) name);
  291.         } 
  292.     }
  293.     SortMenu(theMenu);
  294.     return(heirsUsed);
  295. }
  296.  
  297.  
  298. gxFont DoHierFontMenuCommand(long menuResult, short hierFontMenuID, long *instanceIndex)
  299. {
  300.     short   theItem = LoWord (menuResult);
  301.     short   theMenuID = HiWord (menuResult);
  302.     gxFont        sfnt = 0;
  303.     Str255  str;
  304.     Str255  regStr = "\pRegular";
  305.  
  306.     *instanceIndex = 0;
  307.     
  308.     if( theMenuID == hierFontMenuID)
  309.     {
  310. #if !defined(__powerc) && !defined(ppcinterfaces)
  311.         GetItem(GetMHandle(theMenuID), theItem, str);
  312. #else
  313.         GetMenuItemText(GetMenuHandle(theMenuID), theItem, str);
  314. #endif
  315.         GXFindFonts(nil, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, str[0], str+1, 1,1,&sfnt);
  316.         GXFindFonts(sfnt, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, regStr[0], regStr+1, 1,1,&sfnt);
  317.     }
  318.     else if( theMenuID==0)  /*check if the mouseup was on a family name, if so set sfnt to plain of family???*/
  319.     {
  320.         long mResult = MenuChoice();
  321.         theItem = LoWord (mResult);
  322.         theMenuID = HiWord (mResult);
  323.         if( (theMenuID == hierFontMenuID) && (theItem!=0) )/*could be zero from some other menu*/
  324.         {
  325. #if !defined(__powerc) && !defined(ppcinterfaces)
  326.             GetItem(GetMHandle(theMenuID), theItem, str);
  327. #else
  328.             GetMenuItemText(GetMenuHandle(theMenuID), theItem, str);
  329. #endif
  330.             GXFindFonts(nil, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, str[0], str+1, 1,1,&sfnt);
  331.             GXFindFonts(sfnt, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, regStr[0], regStr+1, 1,1,&sfnt);
  332.         }
  333.     }
  334. /* else if( (theMenuID>0) && (theMenuID<235) && (*( (short*)(0x00000a26) ) == hierFontMenuID) )  // range of hierarchial submenus && owner == hierFontMenuID*/
  335.     else if( (theMenuID>0) && (theMenuID<235) ) /*range of hierarchial submenus && assume owner is hierfontMenuID*/
  336.     {               
  337.         MenuHandle  mh;
  338.         long    index;
  339.         
  340. #if !defined(__powerc) && !defined(ppcinterfaces)
  341.         mh = GetMHandle(theMenuID);
  342. #else
  343.         mh = GetMenuHandle(theMenuID);
  344. #endif
  345.         MoveHHi((Handle)mh);
  346.         HLock((Handle)mh);
  347.         BlockMove ( (**mh).menuData, str, (**mh).menuData[0]+1 );   /*the title of gxStyle menu is the family name*/
  348.         HUnlock((Handle)mh);
  349.         GXFindFonts(nil, gxFamilyFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, str[0], str+1, 1,1,&sfnt);
  350.         
  351.         index = theItem - (CountMItems( mh ) - GXCountFontInstances(sfnt)) ;
  352.         if (index>0)    /*it's an instance*/
  353.             *instanceIndex = index;
  354.         else
  355.         {   /*find by gxFont gxStyle name*/
  356.             gxFont    fontID;
  357.  
  358. #if !defined(__powerc) && !defined(ppcinterfaces)
  359.             GetItem(mh, theItem, str);
  360.  #else
  361.             GetMenuItemText(mh, theItem, str);
  362.  #endif
  363.             GXFindFonts(sfnt, gxStyleFontName, gxMacintoshPlatform, gxRomanScript, gxEnglishLanguage, str[0], str+1, 1,1,&fontID);
  364.             sfnt =fontID;
  365.         }
  366.     }           
  367.     HiliteMenu (0);
  368.     return(sfnt);
  369. }
  370.  
  371. short DoHierFontMenuCommandStyle(long menuResult, short hierFontMenuID,gxStyle aStyle, long matchInfo)
  372. {
  373.     short   theItem = LoWord (menuResult);
  374.     short   theMenuID = HiWord (menuResult);
  375.     gxFont        sfnt;
  376.     short   success = true;
  377.     long        instanceIndex;
  378.  
  379.     sfnt = DoHierFontMenuCommand(menuResult,  hierFontMenuID,  &instanceIndex);
  380.     if (sfnt)
  381.     {
  382.         if(matchInfo && ( (theMenuID == hierFontMenuID) || (theItem == 0) ))/*theItem was on the family name*/
  383.         {
  384.             SetMatchingStyle(sfnt, aStyle, matchInfo);
  385.         }
  386.         else/*no gxStyle matching*/
  387.         {
  388.             GXSetStyleFont(aStyle, sfnt);
  389.             if(instanceIndex)
  390.             {
  391.                 long            howManyVariations;
  392.                 gxFontVariation   *variations;
  393.             
  394.                 howManyVariations = GXCountFontVariations(sfnt); 
  395.                 variations = (gxFontVariation*)NewPtr(sizeof(gxFontVariation) * howManyVariations);
  396.                 GXGetFontInstance(sfnt, instanceIndex, variations);
  397.                 GXSetStyleFont(aStyle, sfnt);
  398.                 GXSetStyleFontVariations(aStyle, howManyVariations, variations);
  399.                 DisposePtr((Ptr)variations);
  400.             }
  401.             else
  402.                 GXSetStyleFontVariations(aStyle, 0, nil);
  403.         }
  404.     }
  405.     else    /*not our menu*/
  406.         success = false;
  407.     
  408.     HiliteMenu (0);
  409.     return(success);
  410. }
  411.  
  412. short DoHierFontMenuCommandShape(long menuResult, short hierFontMenuID,gxShape aShape)
  413. {
  414.     short   theItem = LoWord (menuResult);
  415.     short   theMenuID = HiWord (menuResult);
  416.     gxFont        sfnt;
  417.     short   success = true;
  418.     long        instanceIndex;
  419.  
  420.     sfnt = DoHierFontMenuCommand(menuResult,  hierFontMenuID,  &instanceIndex);
  421.     if (sfnt)
  422.     {
  423.         GXSetShapeFont(aShape, sfnt);
  424.         if(instanceIndex)
  425.         {
  426.             long            howManyVariations;
  427.             gxFontVariation   *variations;
  428.         
  429.             howManyVariations = GXCountFontVariations(sfnt); 
  430.             variations = (gxFontVariation*)NewPtr(sizeof(gxFontVariation) * howManyVariations);
  431.             GXGetFontInstance(sfnt, instanceIndex, variations);
  432.             GXSetShapeFont(aShape, sfnt);
  433.             GXSetShapeFontVariations(aShape, howManyVariations, variations);
  434.             DisposePtr((Ptr)variations);
  435.         }
  436.         else
  437.             GXSetShapeFontVariations(aShape, 0, nil);
  438.     }
  439.     else    /*not our menu*/
  440.         success = false;
  441.     
  442.     HiliteMenu (0);
  443.     return(success);
  444. }
  445.  
  446. long FontToQD(gxFont fontID, long* styleBits)
  447. {
  448.     short resID, i, count;
  449.     OSType resType;
  450.     Str255 resName;
  451.     Handle sfnt;
  452.  
  453.     if (GXGetFont(fontID, (gxFontStorageReference*)&sfnt, nil) != gxResourceFontStorage)
  454.         goto NOT_FOUND;
  455.     GetResInfo(sfnt, &resID, &resType, resName);
  456.     if (ResError())
  457.         goto NOT_FOUND;
  458.  
  459.     count = CountResources('FOND');
  460.     for (i = 1; i <= count; i++)
  461.     {   Handle fond = GetIndResource('FOND', i);
  462.  
  463.         if (!ResError() && fond && *fond)
  464.             do
  465.             {   short* sp = (short*)(*fond + sizeof(FamRec));
  466.                 int entries = *sp++;
  467.                 
  468.                 for (; entries >= 0; --entries)
  469.                 {   if (*sp == 0 && sp[2] == resID)
  470.                     {   if (styleBits)
  471.                             *styleBits = sp[1];
  472.                         GetResInfo(fond, &resID, &resType, resName);
  473.                         return resID;
  474.                     }
  475.                     sp += 3;        /* three elements in the FAT */
  476.                 }
  477.             } while ((fond = XGetNextFOND(fond)) != 0);
  478.     }
  479. NOT_FOUND:
  480.     return 0;
  481. }
  482.  
  483. /*************** font features *************/
  484.  
  485. long GetMenuRunFeatures(MenuHandle menu, gxFont fontID, gxRunFeature feature[])
  486. {
  487.     long i, featureCount, item, count;
  488.  
  489.     count = 0;
  490.     item = 1;
  491.     featureCount = GXCountFontFeatures(fontID);
  492.     for (i = 1; i <= featureCount; i++)
  493.     {    long settingCount, j;
  494.         gxFontFeature featureType;
  495.         gxFontFeatureSetting* settings;
  496.  
  497.         GXGetFontFeature(fontID, i, nil, &settingCount, nil, &featureType);
  498.         settings = (gxFontFeatureSetting*)NewPtr(settingCount * sizeof(gxFontFeatureSetting));
  499.         GXGetFontFeature(fontID, i, nil, nil, settings, nil);
  500.         for (j = 0; j < settingCount; j++)
  501.         {    short mark;
  502.                     
  503.                     GetItemMark(menu, item, &mark);
  504.                     if (mark)
  505.                     {    if (feature)
  506.                         {    feature[count].featureType = featureType;
  507.                             feature[count].featureSelector = settings[j].setting;
  508.                         }
  509.                         ++count;
  510.                     }
  511.                     ++item;
  512.         }
  513.         DisposePtr((Ptr)settings);
  514.         if (i < featureCount)
  515.             ++item;        /* skip the underline */
  516.     }
  517.     return count;
  518. }
  519.  
  520. static boolean SearchRunFeatures(long count, const gxRunFeature feature[], gxFontFeature featureType, long featureSetting)
  521. {    
  522.     if (count)
  523.     {    const gxRunFeature *stop = feature + count;
  524.         do {
  525.             if (feature->featureType == featureType && feature->featureSelector == featureSetting)
  526.                 return true;
  527.             ++feature;
  528.         } while (feature < stop);
  529.     }
  530.     return false;
  531. }
  532.  
  533. void SetMenuRunFeatures(MenuHandle menu, gxFont fontID, long count, const gxRunFeature feature[])
  534. {
  535.     long i, featureCount, item;
  536.  
  537.     item = 1;
  538.     featureCount = GXCountFontFeatures(fontID);
  539.     for (i = 1; i <= featureCount; i++)
  540.     {    long settingCount, j;
  541.         gxFontFeature featureType;
  542.         gxFontFeatureSetting* settings;
  543.  
  544.         GXGetFontFeature(fontID, i, nil, &settingCount, nil, &featureType);
  545.         settings = (gxFontFeatureSetting*)NewPtr(settingCount * sizeof(gxFontFeatureSetting));
  546.         GXGetFontFeature(fontID, i, nil, nil, settings, nil);
  547.         for (j = 0; j < settingCount; j++)
  548.         {    CheckItem(menu, item, SearchRunFeatures(count, feature, featureType, settings[j].setting));
  549.                     ++item;
  550.         }
  551.         DisposePtr((Ptr)settings);
  552.         if (i < featureCount)
  553.             ++item;        /* skip the underline */
  554.     }
  555. }
  556.  
  557. void FontFeatureMenu(MenuHandle menu, gxFont fontID)
  558. {
  559.     long i, featureCount;
  560.     gxFontName nameID;
  561.     Str255 name;
  562.  
  563.     for (i = CountMItems(menu); i > 0; --i)
  564.         DelMenuItem(menu, i);
  565.     featureCount = GXCountFontFeatures(fontID);
  566.     for (i = 1; i <= featureCount; i++)
  567.     {    long settingCount, j;
  568.         gxFontFeatureSetting* settings;
  569.  
  570.         GXGetFontFeature(fontID, i, nil, &settingCount, nil, nil);
  571.         settings = (gxFontFeatureSetting*)NewPtr(settingCount * sizeof(gxFontFeatureSetting));
  572.         GXGetFontFeature(fontID, i, nil, nil, settings, nil);
  573.         for (j = 0; j < settingCount; j++)
  574.         {    FindFontPName(fontID, settings[j].nameID, name);
  575.                     AppendMenu(menu, name);
  576.         }
  577.         DisposePtr((Ptr)settings);
  578.         if (i < featureCount)
  579.             AppendMenu(menu, "\p(-");
  580.     }
  581. }
  582.  
  583.